package com.totem.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.totem.base.constants.ErrorCode;
import com.totem.base.enums.SwitchEnum;
import com.totem.base.exception.BaseException;
import com.totem.base.model.PageVO;
import com.totem.customer.mapper.TFavoritesMapper;
import com.totem.customer.mapper.TTracksMapper;
import com.totem.customer.model.TFavorites;
import com.totem.customer.model.TTracks;
import com.totem.product.mapper.*;
import com.totem.product.model.*;
import com.totem.product.service.ITProductInvService;
import com.totem.product.service.ITProductSpecService;
import com.totem.product.service.ITProductsService;
import com.totem.product.service.ProductCommonService;
import com.totem.product.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TProductsServiceImpl extends ServiceImpl<TProductMapper, TProducts> implements ITProductsService {
    @Autowired
    private TProductMapper tProductMapper;
    @Autowired
    private TProductUrlMapper tProductUrlMapper;
    @Autowired
    private TProductSpecMapper tProductSpecMapper;
    @Autowired
    private TProductInvMapper tProductInvMapper;
    @Autowired
    private ITProductSpecService itProductSpecService;
    @Autowired
    private ITProductInvService itProductInvService;
    @Autowired
    private TProductDetailMapper tProductDetailMapper;
    @Autowired
    private TFavoritesMapper tFavoritesMapper;
    @Autowired
    private TTracksMapper tTracksMapper;
    @Autowired
    private ProductCommonService productCommonService;
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean createProduct(TProducts tProducts, TProductUrl tProductUrl, List<TProductSpec> specList, TProductDetail tProductDetail) {
        boolean productInsertSuccess = false;
        boolean productUrlInsertSuccess = false;
        boolean productSpecInsertSuccess = false;
        boolean productDetailInsertSuccess = false;
        boolean productInvInsertSuccess = false;
        if(tProducts!=null){
            int effect = tProductMapper.insert(tProducts);
            productInsertSuccess = effect>0;
        }
        if(productInsertSuccess && tProductUrl!=null){
            tProductUrl.setProductId(tProducts.getId());
            int effect = tProductUrlMapper.insert(tProductUrl);
            productUrlInsertSuccess = effect>0;
        }
        if(productInsertSuccess && !CollectionUtils.isEmpty(specList)){
            specList.forEach(spec->{
                spec.setProductId(tProducts.getId());
            });
            productSpecInsertSuccess = itProductSpecService.saveBatch(specList);
            if(productSpecInsertSuccess){
                Map<Long, List<TProductSpec>> specMap = specList.stream().collect(Collectors.groupingBy(TProductSpec::getProductId));
                List<TProductInv> invList = specMap.entrySet().stream().map(entry->{
                    Long productId = entry.getKey();
                    List<TProductSpec> specVOList = entry.getValue();
                    int invNum = specVOList.stream().map(TProductSpec::getInventory).reduce(0, Integer::sum);
                    TProductInv inv = TProductInv.builder()
                            .productId(productId)
                            .freeze(0)
                            .inv(invNum)
                            .usable(invNum)
                            .shelfState(SwitchEnum.OFF.getCode())
                            .build();
                    return inv;
                }).toList();
                productInvInsertSuccess = itProductInvService.saveBatch(invList);
            }
        }
        if(productInsertSuccess && tProductDetail!=null){
            tProductDetail.setProductId(tProducts.getId());
            int effect = tProductDetailMapper.insert(tProductDetail);
            productDetailInsertSuccess = effect>0;
        }
        if(productInsertSuccess && productUrlInsertSuccess && productSpecInsertSuccess
                && productDetailInsertSuccess && productInvInsertSuccess){
            return true;
        }else{
            throw new BaseException(ErrorCode.ADD_DATA_ERROR);
        }
    }

    @Override
    public boolean updateProduct(TProducts tProducts, TProductUrl tProductUrl, List<TProductSpec> specList, TProductDetail tProductDetail) {
        boolean productSuccess = false;
        boolean productUrlSuccess = false;
        boolean productSpecSuccess = false;
        boolean productDetailSuccess = false;
        boolean productInvSuccess = false;
        if(tProducts!=null){
            TProducts product = tProductMapper.selectById(tProducts.getId());
            if(product==null){
                throw new BaseException(ErrorCode.NOT_EXIST_PRODUCT);
            }
            int effect = tProductMapper.updateById(tProducts);
            productSuccess = effect>0;
        }
        if(productSuccess && tProductUrl!=null){
            tProductUrl.setProductId(tProducts.getId());
            int effect = tProductUrlMapper.updateById(tProductUrl);
            productUrlSuccess = effect>0;
        }
        // 修改产品信息是增加规格库存
        if(productSuccess && !CollectionUtils.isEmpty(specList)){
            List<TProductSpec> newSpecList = new ArrayList<>();
            List<TProductSpec> updateSpecList = new ArrayList<>();
            specList.forEach(spec->{
                spec.setProductId(tProducts.getId());
                if(spec.getId()==null||spec.getId()<=0){
                    newSpecList.add(spec);
                }else{
                    updateSpecList.add(spec);
                }
            });
            if(!CollectionUtils.isEmpty(newSpecList)) {
                productSpecSuccess = itProductSpecService.saveBatch(newSpecList);
            }
            if(!CollectionUtils.isEmpty(updateSpecList)) {
                productSpecSuccess = itProductSpecService.updateBatchById(updateSpecList);
            }
            if(productSpecSuccess){
                LambdaQueryWrapper<TProductInv> invQuery = new LambdaQueryWrapper<>();
                invQuery.eq(TProductInv::getProductId, tProducts.getId());
                TProductInv oldInv = tProductInvMapper.selectOne(invQuery);
                if(oldInv==null){
                    throw new BaseException(ErrorCode.NOT_EXIST_PRODUCT_INV);
                }
                Map<Long, List<TProductSpec>> specMap = specList.stream().collect(Collectors.groupingBy(TProductSpec::getProductId));
                List<TProductInv> invList = specMap.entrySet().stream().map(entry->{
                    Long productId = entry.getKey();
                    List<TProductSpec> specVOList = entry.getValue();
                    int usableNum = specVOList.stream().map(TProductSpec::getUsable).reduce(0, Integer::sum);
                    int newInv = oldInv.getInv()+usableNum;
                    int newUsable = oldInv.getUsable()+usableNum;
                    TProductInv inv = TProductInv.builder()
                            .productId(productId)
                            .inv(newInv)
                            .usable(newUsable)
                            .build();
                    return inv;
                }).toList();
                productInvSuccess = itProductInvService.updateBatchById(invList);
            }
        }
        if(productSuccess && tProductDetail!=null){
            tProductDetail.setProductId(tProducts.getId());
            int effect = tProductDetailMapper.updateById(tProductDetail);
            productDetailSuccess = effect>0;
        }
        if(productSuccess && productUrlSuccess && productSpecSuccess
                && productDetailSuccess && productInvSuccess){
            return true;
        }else{
            throw new BaseException(ErrorCode.ADD_DATA_ERROR);
        }
    }

    @Override
    public ProductVO getInfoById(Long productId) {
        List<ProductVO> productVOList = productCommonService.list(List.of(productId));

        if(CollectionUtils.isEmpty(productVOList)){
            return null;
        }else{
            ProductVO vo = productVOList.get(0);
            ProductSpecVO latest = vo.getLatestProductSpecVO();
            latest.setCdkey("");
            vo.getProductSpecVOList().forEach(s->{
                s.setCdkey("");
            });
            return vo;
        }
    }

    @Override
    public ProductVO adminGetInfoById(Long productId) {
        List<ProductVO> productVOList = productCommonService.list(List.of(productId));

        if(CollectionUtils.isEmpty(productVOList)){
            return null;
        }else{
            ProductVO vo = productVOList.get(0);
            return vo;
        }
    }

    @Override
    public PageVO<ProductVO> productPage(ProductPageVO vo) {
        String shelfState = vo.getShelfState();
        SwitchEnum switchEnum = SwitchEnum.byCode(shelfState);
        if(switchEnum==null){
            log.warn("上下架状态异常,不支持[{}]", shelfState);
            throw new BaseException(ErrorCode.ILLEGAL_SWITCH);
        }

        List<ProductVO> productVOList = productCommonService.list(vo);
        if(!CollectionUtils.isEmpty(productVOList)){
            productVOList.forEach(p->{
                ProductSpecVO latest = p.getLatestProductSpecVO();
                latest.setCdkey("");
                p.getProductSpecVOList().forEach(s->{
                    s.setCdkey("");
                });
            });
        }

        PageVO<ProductVO> pageVO = new PageVO<>();
        pageVO.setList(productVOList);
        pageVO.setTotal(vo.getTotal());
        return pageVO;
    }

    @Override
    public PageVO<ProductVO> adminProductPage(ProductPageVO vo) {
        String shelfState = vo.getShelfState();
        SwitchEnum switchEnum = SwitchEnum.byCode(shelfState);
        if(switchEnum==null){
            log.warn("上下架状态异常,不支持[{}]", shelfState);
            throw new BaseException(ErrorCode.ILLEGAL_SWITCH);
        }

        List<ProductVO> productVOList = productCommonService.list(vo);

        PageVO<ProductVO> pageVO = new PageVO<>();
        pageVO.setList(productVOList);
        pageVO.setTotal(vo.getTotal());
        return pageVO;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public Boolean delete(ProductDeleteVO vo) {
        if(vo.getProductId()==null){
            throw new BaseException(ErrorCode.REQUIRED_PRODUCT_ID);
        }
        Long productId = vo.getProductId();

        LambdaQueryWrapper<TProductSpec> specQuery = new LambdaQueryWrapper<>();
        specQuery.eq(TProductSpec::getProductId, productId);
        List<TProductSpec> specList = tProductSpecMapper.selectList(specQuery);
        if(!CollectionUtils.isEmpty(specList)){
            List<Long> specIdList = specList.stream().map(TProductSpec::getId).toList();
            tProductSpecMapper.deleteBatchIds(specIdList);
        }
        LambdaQueryWrapper<TProductInv> invQuery = new LambdaQueryWrapper<>();
        invQuery.eq(TProductInv::getProductId, productId);
        TProductInv inv = tProductInvMapper.selectOne(invQuery);
        if(inv!=null){
            tProductInvMapper.deleteById(inv);
        }
        tProductMapper.deleteById(productId);
        tProductUrlMapper.deleteById(productId);
        tProductDetailMapper.deleteById(productId);

        // 删除关联数据
        LambdaQueryWrapper<TFavorites> favQuer = new LambdaQueryWrapper<>();
        favQuer.eq(TFavorites::getProductId, productId);
        List<TFavorites> favList = tFavoritesMapper.selectList(favQuer);
        if(!CollectionUtils.isEmpty(favList)){
            List<Long> idList = favList.stream().map(TFavorites::getId).toList();
            tFavoritesMapper.deleteBatchIds(idList);
        }

        LambdaQueryWrapper<TTracks> trackQuer = new LambdaQueryWrapper<>();
        trackQuer.eq(TTracks::getProductId, productId);
        List<TTracks> trackList = tTracksMapper.selectList(trackQuer);
        if(!CollectionUtils.isEmpty(trackList)){
            List<Long> idList = trackList.stream().map(TTracks::getId).toList();
            tTracksMapper.deleteBatchIds(idList);
        }
        return true;
    }

    @Override
    public Boolean shelf(ProductShelfVO vo) {
        if(vo.getProductId()==null){
            throw new BaseException(ErrorCode.REQUIRED_PRODUCT_ID);
        }
        String shelfState = vo.getShelfState();
        SwitchEnum switchEnum = SwitchEnum.byCode(shelfState);
        if(switchEnum==null){
            log.warn("上下架状态异常,不支持[{}]", shelfState);
            throw new BaseException(ErrorCode.ILLEGAL_SWITCH);
        }
        LambdaQueryWrapper<TProductInv> invQuery = new LambdaQueryWrapper<>();
        invQuery.eq(TProductInv::getProductId, vo.getProductId());
        TProductInv inv = tProductInvMapper.selectOne(invQuery);
        if(inv!=null) {
            TProductInv updInv = TProductInv.builder()
                    .id(inv.getId())
                    .shelfState(vo.getShelfState())
                    .build();

            int effect = tProductInvMapper.updateById(updInv);
            return effect>0;
        }else {
            throw new BaseException(ErrorCode.NOT_EXIST_PRODUCT_INV);
        }
    }
}
